package com.qfmy.service.impl.common;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qfmy.config.ThreadPoolConfig;
import com.qfmy.config.WeatherConfig;
import com.qfmy.mapper.common.AddressMapper;
import com.qfmy.service.common.WeatherService;
import com.qfmy.vo.common.WeatherVo;
import common.exception.BaseException;
import common.login.LoginUser;
import common.login.LoginUserHolder;
import common.result.ResultCodeEnum;
import lombok.extern.slf4j.Slf4j;
import model.entity.common.Address;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;


/**
 * @author 清风明月
 * @Package com.qfmy.service.impl.common
 * @date 2025/5/18
 * @description 天气
 */
@Slf4j
@Service
@SuppressWarnings("all")
public class WeatherServiceImpl implements WeatherService {

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");


    /**
     * 注入地址mapper
     * @return
     */
    @Autowired
    private AddressMapper addressMapper;
    /**
     * 注入RedisTemplate
     */
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    /**
     * 注入天气配置类
     */
    @Autowired
    private WeatherConfig weatherConfig;

    /**
     * 获取天气
     *
     * @return
     */
    @Override
    public WeatherVo getWeather() {
        //获取当前用户id
        Long userId = getUserId();
        //创建redis的key
        String key = "weather:" + userId;
        //从redis中获取天气信息
        WeatherVo weather = (WeatherVo)redisTemplate.opsForValue().get(key);
        if (weather != null) {
            return weather;
        }
        //根据用户id获取地址信息
        Address address = addressMapper.getAddress(userId);
        //获取行政编码
        String cityCode = address.getZipCode();
        //调用百度天气API获取天气数据
        WeatherVo weatherVo = fetchWeatherData(cityCode);
        //异步将天气数据存入redis
        CompletableFuture.runAsync(()->{
            //将数据保存到redis中
            redisTemplate.opsForValue().set(key,weatherVo,12, TimeUnit.HOURS);
        }, ThreadPoolConfig.executorService);
        return weatherVo;
    }

    /**
     * 获取一周天气
     * @return
     */
    @Override
    public List<WeatherVo> getWeekWeather() {
        //获取用户id
        Long userId = getUserId();
        //创建redis的key
        String key = "weathers:" + userId;
        //从redis里面获取天气数据
        List<WeatherVo> weathers = (List<WeatherVo>) redisTemplate.opsForValue().get(key);
        if (weathers != null && weathers.size() > 0) {
            return weathers;
        }
        //获取区域编码
        Address address = addressMapper.getAddress(userId);
        String areaCode = address.getZipCode();
        //获取天气数据
        List<WeatherVo> weatherVos = fetchWeathers(areaCode);
        CompletableFuture.runAsync(()->{
            //将天气数据存入redis
            redisTemplate.opsForValue().set(key, weatherVos, 12, TimeUnit.HOURS);
        },  ThreadPoolConfig.executorService);
        return weatherVos;
    }

    /**
     * 获取一周的天气数据
     *
     * @param areaCode 地区编码
     * @return 一周的天气数据列表
     */
    public List<WeatherVo> fetchWeathers(String areaCode) {
        List<WeatherVo> weatherList = new ArrayList<>();
        try {
            // 构建百度天气API请求URL
            String url = String.format(
                    "https://api.map.baidu.com/weather/v1/?district_id=%s&data_type=all&output=json&ak=%s",
                    areaCode,
                    weatherConfig.getAppKey()
            );

            log.info("调用百度天气API，URL：{}", url);

            // 发送HTTP请求
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);

            // 检查HTTP响应状态
            if (!response.getStatusCode().is2xxSuccessful()) {
                log.warn("百度天气API请求失败，HTTP状态码：{}", response.getStatusCodeValue());
                return weatherList;
            }

            // 解析JSON响应
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode rootNode = objectMapper.readTree(response.getBody());

            // 检查API调用状态
            int apiStatus = rootNode.get("status").asInt();
            if (apiStatus != 0) {
                log.warn("百度天气API调用失败，状态码：{}，消息：{}",
                        apiStatus,
                        rootNode.get("message").asText()
                );
                return weatherList;
            }

            // 提取天气数据
            JsonNode resultNode = rootNode.get("result");
            JsonNode locationNode = resultNode.get("location");
            JsonNode forecastsNode = resultNode.get("forecasts");

            // 解析预报天气数据
            for (JsonNode forecastNode : forecastsNode) {
                WeatherVo forecastWeather = parseForecastWeather(locationNode, forecastNode);
                weatherList.add(forecastWeather);
            }

            return weatherList;

        } catch (Exception e) {
            log.error("获取天气数据时发生异常", e);
            return weatherList;
        }
    }

    /**
     * 解析预报天气数据
     *
     * @param locationNode 位置信息节点
     * @param forecastNode 预报天气节点
     * @return 预报天气数据
     * @throws ParseException 解析异常
     */
    @NotNull
    private WeatherVo parseForecastWeather(@NotNull JsonNode locationNode, JsonNode forecastNode) throws ParseException {
        WeatherVo weatherVo = new WeatherVo();
        // 基本信息
        weatherVo.setCityName(locationNode.get("name").asText());
        weatherVo.setWeatherCondition(forecastNode.get("text_day").asText() + "转" + forecastNode.get("text_night").asText());
        weatherVo.setMaxTemperature(new BigDecimal(forecastNode.get("high").asText()));
        weatherVo.setMinTemperature(new BigDecimal(forecastNode.get("low").asText()));
        weatherVo.setWindDirection(forecastNode.get("wd_day").asText());
        weatherVo.setWeek(forecastNode.get("week").asText());
        weatherVo.setDay(forecastNode.get("date").asText());



        // 风速处理
        double windSpeedDayKmh = convertWindClassToKmh(forecastNode.get("wc_day").asText());
        double windSpeedNightKmh = convertWindClassToKmh(forecastNode.get("wc_night").asText());
        weatherVo.setWindForce(BigDecimal.valueOf((windSpeedDayKmh + windSpeedNightKmh) / 2)); // 取平均值

        // 日期处理
        String dateStr = forecastNode.get("date").asText().substring(0, 10).replace("-", "");
        Date forecastDate = sdf.parse(dateStr);
        weatherVo.setDate(forecastDate);

        return weatherVo;
    }


    /**
     * 调用百度天气API获取天气数据
     * @param areaCode 区域编码
     * @return WeatherVo 对象，获取失败返回 null
     */
    @Nullable
    private WeatherVo fetchWeatherData(String areaCode) {
        try {
            // 构建百度天气API请求URL
            String url = String.format(
                    "https://api.map.baidu.com/weather/v1/?district_id=%s&data_type=now&output=json&ak=%s",
                    areaCode,
                    weatherConfig.getAppKey()
            );

            log.info("调用百度天气API，URL：{}", url);

            // 发送HTTP请求
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);

            // 检查HTTP响应状态
            if (!response.getStatusCode().is2xxSuccessful()) {
                log.warn("百度天气API请求失败，HTTP状态码：{}", response.getStatusCodeValue());
                return null;
            }

            // 解析JSON响应
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode rootNode = objectMapper.readTree(response.getBody());

            // 检查API调用状态
            int apiStatus = rootNode.get("status").asInt();
            if (apiStatus != 0) {
                log.warn("百度天气API调用失败，状态码：{}，消息：{}",
                        apiStatus,
                        rootNode.get("message").asText()
                );
                return null;
            }

            // 提取天气数据
            JsonNode resultNode = rootNode.get("result");
            JsonNode nowNode = resultNode.get("now");
            JsonNode locationNode = resultNode.get("location");
            log.info("获取天气数据成功：{}", resultNode);

            // 创建WeatherVo对象
            WeatherVo weatherVo = new WeatherVo();

            // 基本信息
            weatherVo.setCityName(locationNode.get("name").asText());
            weatherVo.setCurrentTemperature(new BigDecimal(nowNode.get("temp").asText()));
            weatherVo.setWeatherCondition(nowNode.get("text").asText());
            weatherVo.setHumidity(nowNode.get("rh").asInt());

            // 风速处理 - 将文本描述转为千米每小时的数值
            String windClass = nowNode.get("wind_class").asText().replaceAll("[^0-9]", "");
            //解析风速
            weatherVo.setWindForce(BigDecimal.valueOf(convertWindClassToKmh(windClass)));

            // 日期处理
            String uptime = nowNode.get("uptime").asText();
            Date currentDate = sdf.parse(uptime.substring(0, 10));
            weatherVo.setDate(currentDate);


            log.info("成功获取天气数据，地区：{}", weatherVo.getCityName());
            return weatherVo;

        } catch (Exception e) {
            log.error("获取天气数据时发生异常", e);
            return null;
        }
    }

    /**
     * 将风速等级文本转换为千米每小时数值
     * @param windClassText 风速等级文本
     * @return 风速（千米每小时）
     */
    private double convertWindClassToKmh(@NotNull String windClassText) {
        String windClass = windClassText.replaceAll("[^0-9]", "");
        int windLevel = windClass.isEmpty() ? 0 : Integer.parseInt(windClass);

        switch (windLevel) {
            case 0:
                return 0.0;
            case 1:
                return 3.2; // 1级风的平均值
            case 2:
                return 8.3; // 2级风的平均值
            case 3:
                return 15.4; // 3级风的平均值
            case 4:
                return 24.1; // 4级风的平均值
            case 5:
                return 33.8; // 5级风的平均值
            case 6:
                return 44.0; // 6级风的平均值
            case 7:
                return 55.3; // 7级风的平均值
            case 8:
                return 67.8; // 8级风的平均值
            case 9:
                return 81.5; // 9级风的平均值
            case 10:
                return 95.4; // 10级风的平均值
            case 11:
                return 110.0; // 11级风的平均值
            case 12:
                return 130.0; // 12级风及以上的平均值
            default:
                return 0.0; // 默认值
        }
    }


    /**
     * 获取当前用户id
     * @return
     */
    @Nullable
    @Contract(pure = true)
    private Long getUserId() {
        //获取当前用户的id
        LoginUser loginUser = LoginUserHolder.getLoginUser();
        if (loginUser == null) {
           throw new BaseException(ResultCodeEnum.TOKEN_INVALID);
        }
        return loginUser.getUserId();
    }
}
